home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / modelers / chmsthtc / chmsthtc.lzh / Chemesthetics / Source / Source.LZH / chemest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-22  |  24.5 KB  |  1,033 lines

  1. /* $Revision Header *** Header built automatically - do not edit! ***********
  2.  *
  3.  *    (C) Copyright 1991 by Metalworx
  4.  *
  5.  *    Name .....: chemest.c
  6.  *    Created ..: Sun 06-Oct-91 20:51
  7.  *    Revision .: 2
  8.  *
  9.  *    Date        Author        Comment
  10.  *    =========    ========    ====================
  11.  *    23-Oct-91    Mtwx        FileRequest-Struktur jetzt ⁿber ArpAlloc()
  12.  *    18-Oct-91    Mtwx        Zeit-Info hinzugefⁿgt
  13.  *         1989    Mtwx        Created this file!
  14.  *
  15.  * $Revision Header ********************************************************/
  16.  #define REVISION 2
  17.  
  18. /***************************************************************************
  19. * chemest.c : Hauptprogramm von Chemesthetics                   *
  20. ***************************************************************************/
  21.  
  22. /* ------------------------------- includes ----------------------------- */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <intuition/intuitionbase.h>
  27. #include <graphics/gfxbase.h>
  28. #include <libraries/dosextens.h>
  29. #include <libraries/mathffp.h>
  30. #include <libraries/arpbase.h>
  31. #include <libraries/reqbase.h>
  32. #include <clib/req_protos.h>
  33. #include <req.h>
  34. #include <exec/memory.h>
  35. #include <time.h>
  36. #include <proto/dos.h>
  37. #include <proto/exec.h>
  38. #include <proto/intuition.h>
  39. #include <proto/graphics.h>
  40.  
  41. #include <mtwx_defs.h>
  42.  
  43. #include "messages.h"
  44. #include "chem_defs.h"
  45. #include "chemest.h"
  46.  
  47. /* ------------------------------- defines ------------------------------ */
  48.  
  49. #define OK 0
  50. #define NOK 1
  51. #define RESX 640.0               /* Breite des Bildes */
  52.  
  53. double      VERGRFAKTOR = 0.3;           /* Umrechnungsfaktor pm -> Pixels   */
  54.  
  55. int      HEIGHT = 256;            /* Default, wird bei NTSC-Screen geaendert */
  56. BOOL      reflexion = FALSE, reqlib_used=FALSE;
  57. int      koordmx, koordmy, n, ref;
  58. int      reflexionsfarbe, schattenfarbe, aktfarb, beanz;    /*Anzahl der Kalotten, die
  59.                            das betrachtete Atom
  60.                            berhren bzw. schneiden*/
  61.  
  62. double      mattheit, matthm1, abstand, aspect, vergr, zf;
  63. int      drehx = 0, drehy = 0, drehz = 0;
  64.  
  65. VEKTOR      l, b;                /*Lichtquelle, Beobachter*/
  66.  
  67. int      atomanz;               /*Anzahl der Atome    */
  68. int      geladene_Atome;           /* Anzahl der Atome im Datenfile */
  69.  
  70. ATOMTYP   *a[MAXATOM],*alt[MAXATOM];   /* Atome */
  71.  
  72. T_MB      mb;                   /*moegliche Beruehrungen*/
  73.  
  74. long      conwin;
  75. char      dn[DSIZE+FCHARS+2]="";
  76. char      Dateiname[FCHARS+1]="", IFFDateiname[FCHARS+1];
  77. char      Pfadname[DSIZE+1],Titel[80];
  78. UBYTE     *atomliste[105];
  79. USHORT      code;
  80. USHORT      GadgetID;
  81.  
  82. struct Atom *GAtom[106];
  83. struct ChemPrefs ChemPrefs= { 1.5,TRUE,TRUE,FALSE,TRUE };
  84. struct IntuitionBase *IntuitionBase;
  85. struct GfxBase *GfxBase;
  86. struct ArpBase *ArpBase;
  87. struct ReqLib *ReqBase;
  88. struct Screen *FirstScreen;
  89. struct Window *Window1, *Window2;
  90. struct IntuiMessage *message;
  91. struct Gadget *GadgetPtr;
  92. struct Process *MyProcess;
  93. struct ReqFileRequester *FileStr; /* kommt aus reqbase.h */
  94. FILE *datei;
  95. APTR OldErrorWin;          /* Windowstruktur vor dem Starten des Tasks */
  96.  
  97. /* ------------------------------- external references ------------------ */
  98.  
  99. extern char ProgId[], Version[];
  100. extern struct Window *timewin;
  101.  
  102. /* ------------------------------- prototypes --------------------------- */
  103.  
  104. /* Prototypes for functions defined in chemest.c */
  105.  
  106. #ifndef __NOPROTO
  107. #ifndef __PROTO
  108. #define __PROTO(a) a
  109. #endif
  110. #else
  111. #ifndef __PROTO
  112. #define __PROTO(a) ()
  113. #endif
  114. #endif
  115.  
  116. void Load_Datafile __PROTO((void));
  117. void Farben __PROTO((void));
  118. void set_screenmode __PROTO((int height));
  119. void bringeaufeinheitsvektor __PROTO((register VEKTOR *v));
  120. double cowinkelzwischen __PROTO((VEKTOR *v_v1, VEKTOR *v_v2));
  121. void plot __PROTO((double x, double y, double hell1, double hell2));
  122. void spiegle __PROTO((VEKTOR *v_v2, VEKTOR *v1));
  123. void moeglicheberuehrungentesten __PROTO((void));
  124. BOOL beruehrung __PROTO((double x, double y, double z));
  125. int __regargs atomzeichnen __PROTO((ATOMTYP *v_m));
  126. void atomskizze __PROTO((ATOMTYP *v_m));
  127. void atomeordnen __PROTO((void));
  128. void atomezentrieren __PROTO((void));
  129. void atomedrehen __PROTO((char achse, double dx));
  130. int farbnr __PROTO((ATOMTYP *v_atom));
  131. void PrintName __PROTO((void));
  132. void Werte_loeschen __PROTO((void));
  133. void Menu_Auswertung __PROTO((USHORT Menu_Nr));
  134. void main __PROTO((void));
  135. int Nachricht __PROTO((struct Window *win));
  136. void Open_All __PROTO((void));
  137. void Close_All __PROTO((BOOL status));
  138.  
  139. /* ------------------------------- external references ------------------ */
  140.  
  141. extern void Prepare(),PrepareLogo(),FreeLogo(),PrepareEGadgets(),
  142.         FreeEGadgets(),floh(),StatRequest(),license(),SimpleRequest(),
  143.         SysInfo();
  144. extern int dateieinlesen __PROTO((void));
  145. extern void dateispeichern __PROTO((BOOL));
  146. extern void Bild_speichern __PROTO((void));
  147. extern void zeit_angabe __PROTO((int,long,long));
  148. extern BOOL prepare_zeitinfo __PROTO((int));
  149. extern long save();
  150. extern short TwoGadRequest();
  151. extern double bildverh();
  152.  
  153. /* --------- Menuefunktionen ----------------------------------------*/
  154.  
  155.  
  156. void      Load_Datafile()
  157. {
  158.   int        i;
  159.   char       dummy[20];
  160.  
  161. #ifdef GERMAN
  162.   datei = fopen("chems_g.dat", "r");
  163. #endif
  164. #ifdef ENGLISH
  165.   datei = fopen("chems_e.dat", "r");
  166. #endif
  167.   if (datei)
  168.   {
  169.     WrConWin(conwin, READING_DATA);
  170.     fgets(dummy,19,datei); geladene_Atome=atoi(dummy);
  171.     for (i = 1; i <= geladene_Atome; i++)
  172.     {
  173.       GAtom[i] = (struct Atom *) ArpAlloc(sizeof(struct Atom));
  174.       if (GAtom[i] == NULL)
  175.       {
  176.     WrConWin(conwin, ERROR_NO_MEM);
  177.     DisplayAlert(RECOVERY_ALERT,
  178. #ifdef GERMAN
  179.              "\1\0\30 Kein Speicher fuer Daten-File\0c\1\0\50 Maustaste druecken.\0\0",
  180. #endif
  181. #ifdef ENGLISH
  182.              "\1\0\30 No memory for data file\0c\1\0\50 Click mouse button.\0\0",
  183. #endif
  184.              70);
  185.     Close_All(NOK);
  186.       }
  187.       fgets(GAtom[i]->Kurzz, 4, datei);
  188.       GAtom[i]->Kurzz[strlen(GAtom[i]->Kurzz) - 1] = '\0';
  189.       fgets(GAtom[i]->Name, 21, datei);
  190.       atomliste[i - 1] = (UBYTE *) GAtom[i]->Name;
  191.       GAtom[i]->Name[strlen(GAtom[i]->Name) - 1] = '\0';
  192.       fgets(dummy,19,datei); GAtom[i]->Farbe=atoi(dummy);
  193.     }
  194.     GAtom[105] = (struct Atom *) ArpAlloc(sizeof(struct Atom));
  195.     strcpy(GAtom[105]->Name, "??????????");
  196.     fclose(datei);
  197.     WrConWin(conwin, "ok\n");
  198.   }
  199.   else
  200.   {
  201.     WrConWin(conwin, ERROR_OPEN_DATA);
  202.     Delay(150L);
  203.     Close_All(NOK);
  204.   }
  205. }
  206.  
  207. void      Farben()
  208. {
  209.   int        rwert;
  210.  
  211.   rwert = palette_request(Window1, -1, -1, PALETTE_REQ, "DEFAULT", 4);
  212.   if (rwert == 5)                      /* Default Farben! */
  213.     LoadRGB4(&FirstScreen->ViewPort, &Def_Pal[0], 16);
  214. }
  215.  
  216. void set_screenmode(height) /* undokumentiert!!, Σndert Screen in NTSC-
  217.                    oder PAL-Screen, je nach 'height' */
  218. int height;
  219. {
  220.   MyProcess->pr_WindowPtr=OldErrorWin;
  221.  
  222.   if (Window1)
  223.     ClearMenuStrip(Window1);
  224.   if (Window1)
  225.     CloseWindowSafely(Window1, NULL);
  226.   if (FirstScreen)
  227.     CloseScreen(FirstScreen);
  228.   HEIGHT=height;
  229.   if((HEIGHT > 200) && (GfxBase->DisplayFlags & (UWORD)NTSC))
  230.     HEIGHT=200;
  231.   FirstNewScreen.Height = HEIGHT;
  232.   if (!(FirstScreen = (struct Screen *)
  233.     OpenScreen(&FirstNewScreen)))
  234.   {
  235.     WrConWin(conwin, NO_SCREEN);
  236.     Delay(150L);
  237.     Close_All(NOK);
  238.   }
  239.   LoadRGB4(&FirstScreen->ViewPort, &Pal[0], 16);
  240.   HauptFenster.Height = HEIGHT;
  241.   HauptFenster.Screen = FirstScreen;
  242.   if (!(Window1 = (struct Window *)
  243.     OpenWindow(&HauptFenster)))
  244.   {
  245.     WrConWin(conwin, NO_MAIN_WIN);
  246.     Delay(150L);
  247.     Close_All(NOK);
  248.   }
  249.   SetMenuStrip(Window1, &Menu1);
  250.   MyProcess = (struct Process *)FindTask((char *)0);
  251.   OldErrorWin = MyProcess->pr_WindowPtr; /* alten Window-Pointer sichern */
  252.   MyProcess->pr_WindowPtr=(APTR) Window1; /* Requests auf neuen Screen */
  253.   koordmy = round(((double) HEIGHT - 26.0) / 2.0);
  254.   if(HEIGHT<256)
  255.     ChemPrefs.bv=2.0;
  256.   else
  257.     ChemPrefs.bv=1.5;
  258.   aspect = ((double) HEIGHT - 26.0) / RESX * ChemPrefs.bv;
  259.   ShowTitle(FirstScreen,ChemPrefs.Title);
  260. }
  261.  
  262. /* --------- interne Programmroutinen -------------------------------*/
  263.  
  264. void      bringeaufeinheitsvektor(v)
  265. register VEKTOR   *v;
  266.  
  267. /* Der Vektor wird durch seine Laenge dividiert
  268.      und erhaelt dadurch die Laenge 1         */
  269. {
  270.   register double    r;             /*Laenge*/
  271.  
  272.   r = sqrt((float)(v->x * v->x + v->y * v->y + v->z * v->z));
  273.   if (r > 0.0)
  274.   {
  275.     v->x = v->x / r;
  276.     v->y = v->y / r;
  277.     v->z = v->z / r;
  278.   }
  279. }
  280.  
  281.  
  282. double      cowinkelzwischen(v_v1, v_v2)
  283. VEKTOR     *v_v1, *v_v2;
  284.  
  285. /* Cosinus des Winkels zwischen den Vektoren v1 und v2 */
  286. {
  287.   double    r_cowinkelzwischen;
  288.   VEKTOR    v1, v2;
  289.  
  290.   v1 = *v_v1;
  291.   v2 = *v_v2;
  292.   bringeaufeinheitsvektor(&v1);
  293.   bringeaufeinheitsvektor(&v2);
  294.   r_cowinkelzwischen = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  295.   return r_cowinkelzwischen;
  296. }
  297.  
  298.  
  299. void      plot(x, y, hell1, hell2)
  300. double      x, y, hell1, hell2;
  301.  
  302. /* Farbgebung nach Ordered-Dither-Verfahren
  303.      in 17 Helligkeisstufen
  304.   Uebergabe: 0 <= hell <= 16
  305.      hell1: Farbe der Kalotte
  306.      hell2: Spiegelung der Beleuchtung */
  307. {
  308.   typedef char T_FARBMATRIX[4][4];
  309.   static T_FARBMATRIX farbmatrix =
  310.   {
  311.     {0, 8, 2, 10},
  312.     {12, 4, 14, 6},
  313.     {3, 11, 1, 9},
  314.     {15, 7, 13, 5}};
  315.   int        kx, ky;
  316.  
  317.   kx = round(koordmx + x);
  318.   ky = round(koordmy - y);
  319.   if (hell2 > (double) farbmatrix[(kx & 3)][(ky & 3)])
  320.     Pixel(Window1, reflexionsfarbe, kx, ky)     /* Spiegelung */
  321.       ;
  322.   else if (hell1 > (double) farbmatrix[(kx & 3)][(ky & 3)])
  323.     Pixel(Window1, aktfarb, kx, ky)    /* Farbe der Kalotte */
  324.       ;
  325.   else
  326.     Pixel(Window1, schattenfarbe, kx, ky);      /* Schatten */
  327. }
  328.  
  329.  
  330. void      spiegle(v_v2, v1)
  331. VEKTOR     *v_v2, *v1;
  332.  
  333. /* v1 wird an der Ebene gespiegelt, die zu v2 normal steht */
  334. {
  335.   VEKTOR    v2;
  336.   double    coa;               /* 1/Cos des eingeschlossenen Winkels */
  337.  
  338.   v2 = *v_v2;
  339.   bringeaufeinheitsvektor(v1);
  340.   bringeaufeinheitsvektor(&v2);
  341.   coa = -1.0 / (v1->x * v2.x + v1->y * v2.y + v1->z * v2.z);
  342.   v1->x = v1->x * coa + 2.0 * v2.x;
  343.   v1->y = v1->y * coa + 2.0 * v2.y;
  344.   v1->z = v1->z * coa + 2.0 * v2.z;
  345. }
  346.  
  347.  
  348. void      moeglicheberuehrungentesten()
  349. /* laedt die Nummern aller Atome, die das betrachtete Atom
  350.      schneiden oder berhren, ins Array mb */
  351. {
  352.   int        i;
  353.   double    dist;               /* Abstand zwischen den Mittelpunkten des
  354.                     betrachteten und eines anderen Atomes      */
  355.  
  356.   beanz = 0;
  357.   if (n > 1)
  358.   {
  359.     for (i = 1; i <= n - 1; i++)
  360.     {
  361.       dist = (double) ((int) (a[n]->x - a[i]->x) * (int) (a[n]->x - a[i]->x))
  362.     + (double) ((int) (a[n]->y - a[i]->y) * (int) (a[n]->y - a[i]->y))
  363.     + (double) ((int) (a[n]->z - a[i]->z) * (int) (a[n]->z - a[i]->z));
  364.       if (dist < 1e-5)
  365.     dist = 1e-5;
  366.       if (sqrt((float)dist) < (double) ((double) a[i]->r + a[n]->r))
  367.       {
  368.     beanz++;
  369.     mb[beanz] = i;
  370.       }
  371.     }
  372.   }
  373. }
  374.  
  375.  
  376. BOOL     beruehrung(x, y, z)
  377. double      x, y, z;
  378.  
  379. /* testet, ob der Punkt (x,y,z), der auf der Oberflaeche
  380.      der betrachteten Kalotte liegt, eventuell innerhalb einer
  381.      anderen Kalotte liegt und deshalb unsichtbar bleiben muss:
  382.      => Beruehrung := true    */
  383. {
  384.   BOOL        r_beruehrung;
  385.   int        i;
  386.   double    dist;               /*Abstand der Mittelpunkte*/
  387.   BOOL        flag;               /*wird gesetzt, wenn die
  388.                            oben genannte Bedingung zutrifft */
  389.  
  390.   r_beruehrung = FALSE;
  391.   if (beanz > 0)
  392.   {
  393.     i = 1;
  394.     flag = FALSE;
  395.     do
  396.     {
  397.       dist = (x - a[mb[i]]->x) * (x - a[mb[i]]->x)
  398.     + (y - a[mb[i]]->y) * (y - a[mb[i]]->y)
  399.     + (z - a[mb[i]]->z) * (z - a[mb[i]]->z);
  400.       if (dist < 1e-5)
  401.     dist = 1e-5;
  402.       if (sqrt((float)dist) < (double) a[mb[i]]->r)
  403.     flag = TRUE;
  404.       i++;
  405.     } while (!((i > beanz) || flag));
  406.     if (flag)
  407.       r_beruehrung = TRUE;
  408.   }
  409.   return r_beruehrung;
  410. }
  411.  
  412.  
  413. int    __regargs atomzeichnen(v_m)
  414. ATOMTYP  *v_m;
  415.  
  416. /* zeichnet eine Kalotte */
  417. {
  418.   ATOMTYP   m;
  419.   int        xbild, zbild, zmbild, rbild, rzbild, mxbild, mzbild, lirand,
  420.         rerand;               /* Anfang, Ende einer Pixelzeile */
  421.   double    farbe1, farbe2, perspfaktor, vp, avp, r2double, rz2double,
  422.         radbild, r2bild, cowinkel; /* Cosinus               */
  423.   VEKTOR    o, vo, vl, vb, vs;           /* vgl. Skizze!         */
  424.  
  425.   m = *v_m;
  426.   moeglicheberuehrungentesten();
  427.   perspfaktor = abstand / (abstand + m.y);
  428.   vp = vergr * perspfaktor;
  429.   avp = aspect / vp;
  430.   r2double = (double) ((int) (m.r) * (int) (m.r));
  431.   radbild = m.r * vp;
  432.   mxbild = round(m.x / avp);           /*Koordinaten des Mittelpunktes*/
  433.   mzbild = round(m.z * vp);            /*der Kalotte in Pixels        */
  434.   rbild = trunc(radbild);
  435.   r2bild = radbild * radbild;
  436.   for (zbild = rbild; zbild >= -rbild; zbild--)
  437.   {
  438.     vo.z = zbild / vp;
  439.     o.z = vo.z + m.z;
  440.     vl.z = l.z - o.z;
  441.     rz2double = r2double - vo.z * vo.z;
  442.     rzbild = trunc(sqrt((float)(r2bild - (double) (zbild * zbild))) / aspect);
  443.     lirand = 20000;
  444.     rerand = 20000;
  445.     xbild = -rzbild;               /* Feststellen der Raender des
  446.                       sichtbaren Bereiches einer
  447.                       Pixelzeile der Kalotte */
  448.     do
  449.     {
  450.       vo.x = xbild * avp;
  451.       vo.y = -sqrt((float)(rz2double - vo.x * vo.x));
  452.       if (beruehrung(m.x + vo.x, m.y + vo.y, o.z))
  453.     (xbild)++;
  454.       else
  455.     lirand = xbild;
  456.     } while (!((lirand == xbild) || (xbild > rzbild)));
  457.     if (lirand <= rzbild)
  458.     {
  459.       xbild = rzbild;
  460.       do
  461.       {
  462.     vo.x = xbild * avp;
  463.     vo.y = -sqrt((float)(rz2double - vo.x * vo.x));
  464.     if (beruehrung(m.x + vo.x, m.y + vo.y, o.z))
  465.       (xbild)--;
  466.     else
  467.       rerand = xbild;
  468.       } while (!((rerand == xbild) || (xbild < -rzbild)));
  469.       zmbild = zbild + mzbild;           /* Berechnung der Farbe aller sichtbaren Punkte
  470.         der Pixelzeile                  */
  471.       for (xbild = lirand; xbild <= rerand; xbild++)
  472.       {
  473.     farbe2 = 0.0;
  474.     vo.x = xbild * avp;
  475.     vo.y = -sqrt((float)rz2double - vo.x * vo.x);
  476.     o.x = vo.x + m.x;
  477.     o.y = vo.y + m.y;
  478.     vl.x = l.x - o.x;
  479.     vl.y = l.y - o.y;
  480.     cowinkel = cowinkelzwischen(&vl, &vo);
  481.     farbe1 = 16.0 * cowinkel;      /* Reflexion */
  482.     if (reflexion)
  483.       if (cowinkel > 0.0)
  484.       {
  485.         vs = vl;
  486.         spiegle(&vo, &vs);         /*vS enthlt jetzt den gespiegelten Lichtvektor*/
  487.         vb.x = b.x - o.x;
  488.         vb.y = b.y - o.y;
  489.         vb.z = b.z - o.z;
  490.         cowinkel = cowinkelzwischen(&vb, &vs);
  491.         cowinkel = cowinkel / mattheit - matthm1;
  492.         farbe2 = 16.0 * cowinkel;
  493.       }
  494.     plot((double) xbild + mxbild, (double) zmbild, farbe1, farbe2);
  495.     if (message = (struct IntuiMessage *) GetMsg(Window1->UserPort))
  496.     {
  497.       int        nklasse;
  498.  
  499.       nklasse = message->Class;
  500.       code = message->Code;
  501.       GadgetPtr = (struct Gadget *) message->IAddress;
  502.       GadgetID = GadgetPtr->GadgetID;
  503.       ReplyMsg((struct Message*)message);
  504.       while (message = (struct IntuiMessage *) GetMsg(Window1->UserPort))
  505.         ReplyMsg((struct Message*)message);
  506.       return nklasse;
  507.     }
  508.       }
  509.     }
  510.   }
  511.   return 0;
  512. }
  513.  
  514.  
  515. void      atomskizze(v_m)
  516. ATOMTYP  *v_m;
  517.  
  518. /* zeichnet den Umriss einer Kalotte */
  519. {
  520.   ATOMTYP   m;
  521.   double    vp, radbild;           /*Radius der Kalotte am Bild in Pixels    */
  522.  
  523.   m = *v_m;
  524.   vp = vergr * abstand / (abstand + m.y);
  525.   radbild = vp * (double) m.r;
  526.   Ellipse(Window1, aktfarb, koordmx + round(vp * m.x / aspect), koordmy - round(vp * m.z),
  527.     (int) (round(radbild / aspect) - 2.0), (int) (round(radbild) - 2.0));
  528. }
  529.  
  530.  
  531. void      atomeordnen()
  532. /* ordnet die Atome von hinten nach vorne */
  533. {
  534.   int        i;
  535.   ATOMTYP   *zwi;
  536.   BOOL        flag;
  537.  
  538.   do
  539.   {
  540.     flag = FALSE;
  541.     for (i = 1; i <= atomanz - 1; i++)
  542.     {
  543.       if ((a[i]->y < a[i + 1]->y))
  544.       {
  545.     zwi = a[i];
  546.     a[i] = a[i + 1];
  547.     a[i + 1] = zwi;
  548.     flag = TRUE;
  549.       }
  550.     }
  551.   } while (flag != FALSE);
  552. }
  553.  
  554.  
  555. void      atomezentrieren()
  556. /* zentriert die Atome im Koordinatensystem */
  557. {
  558.   int        i, dx, dy, dz, minx, maxx, miny, maxy, minz, maxz;
  559.  
  560.   maxx = -30000;
  561.   maxy = maxx;
  562.   maxz = maxx;
  563.   minx = 30000;
  564.   miny = minx;
  565.   minz = minx;
  566.   for (i = 1; i <= atomanz; i++)
  567.   {
  568.     if (a[i]->x < minx)
  569.       minx = a[i]->x;
  570.     if (a[i]->x > maxx)
  571.       maxx = a[i]->x;
  572.     if (a[i]->y < miny)
  573.       miny = a[i]->y;
  574.     if (a[i]->y > maxy)
  575.       maxy = a[i]->y;
  576.     if (a[i]->z < minz)
  577.       minz = a[i]->z;
  578.     if (a[i]->z > maxz)
  579.       maxz = a[i]->z;
  580.   }
  581.   dx = (int) round(((double) maxx + minx) / 2.0);
  582.   dy = (int) round(((double) maxy + miny) / 2.0);
  583.   dz = (int) round(((double) maxz + minz) / 2.0);
  584.   for (i = 1; i <= atomanz; i++)
  585.   {
  586.     a[i]->x-=dx;
  587.     a[i]->y-=dy;
  588.     a[i]->z-=dz;
  589.   }
  590. }
  591.  
  592.  
  593. void      atomedrehen(achse, dx)
  594. char      achse;
  595. double      dx;
  596.  
  597. /* dreht alle Atome um den Winkel dx
  598.      um die Koordinatenachse "Achse"    */
  599. {
  600.   int        xalt, yalt, zalt, i;
  601.   double    sx, cx;
  602.  
  603.   dx = dx / 180.0 * PI;            /*Umrechnung in rad*/
  604.   sx = sin((float)dx);
  605.   cx = cos((float)dx);
  606.   for (i = 1; i <= atomanz; i++)
  607.   {
  608.     xalt = a[i]->x;
  609.     yalt = a[i]->y;
  610.     zalt = a[i]->z;
  611.     switch (achse)
  612.     {
  613.       case 'x':
  614.     a[i]->y = round(yalt * cx + zalt * sx);
  615.     a[i]->z = round(-yalt * sx + zalt * cx);
  616.     break;
  617.       case 'y':
  618.     a[i]->x = round(xalt * cx - zalt * sx);
  619.     a[i]->z = round(xalt * sx + zalt * cx);
  620.     break;
  621.       case 'z':
  622.     a[i]->x = round(xalt * cx + yalt * sx);
  623.     a[i]->y = round(-xalt * sx + yalt * cx);
  624.     break;
  625.     }
  626.  
  627.   }
  628. }
  629.  
  630. int      farbnr(v_atom)
  631. ATOMTYP  *v_atom;
  632.  
  633.  /* Zuteilung der Farbe einer Kalotte */
  634. {
  635.   register int i;
  636.   int        f;
  637.   ATOMTYP   atom;
  638.  
  639.   f = 0;
  640.   atom = *v_atom;
  641.   /* in diese Tabelle gewuenschte Farben je nach Graphikkarte
  642.      und persoenlichem Geschmack eintragen (nicht Schwarz!)
  643.      und Tabelle nach Bedarf erweitern */
  644.  
  645.   reflexionsfarbe = 2;
  646.   schattenfarbe = 1;
  647.   for (i = 1; i <= geladene_Atome; i++)
  648.   {
  649.     if (!stricmp(atom.name, GAtom[i]->Kurzz))
  650.     {
  651.       f = GAtom[i]->Farbe;
  652.       i = geladene_Atome;
  653.     }
  654.   }
  655.   if (f == 0)
  656.   {
  657.     SimpleRequest("%s %s", NO_ATOM, atom.name);
  658.     return (7);                        /* als default nehmen */
  659.   }
  660.   else
  661.     return (f);
  662. }
  663.  
  664. void      PrintName()
  665. {
  666.   int        i;
  667.   char        dummy[31];
  668.  
  669.   i = strpos(Dateiname, ".");
  670.   if (i > 0)
  671.   {
  672.     strncpy(dummy, Dateiname, i);
  673.     dummy[i] = '\0';
  674.   }
  675.   else
  676.     strcpy(dummy, Dateiname);
  677.   Shadow(Window1, dummy, 1, 13, 20, HEIGHT - 6);
  678. }
  679.  
  680. void      Werte_loeschen()
  681. {
  682.   register int i;
  683.  
  684.   for (i = 1; i <= atomanz; i++)
  685.   {
  686.     setmem(alt[i],sizeof(ATOMTYP),NULL);
  687.     setmem(a[i],sizeof(ATOMTYP),NULL);
  688.   }
  689.   zf = 1.0;
  690.   drehx = 0;
  691.   drehy = 0;
  692.   drehz = 0;
  693.   l.x = 20000.0;
  694.   l.y = -100000.0;
  695.   l.z = 20000.0;
  696.   ref = 0;
  697. }
  698.  
  699. void Menu_Auswertung(Menu_Nr)
  700. USHORT      Menu_Nr;
  701. {
  702.   USHORT    Menu, MenuItem;
  703.   long stime,etime;
  704.   BOOL timewindow_on=FALSE;
  705.  
  706.   Menu = MENUNUM(Menu_Nr);
  707.   MenuItem = ITEMNUM(Menu_Nr);
  708. /*  SubItem = SUBNUM(Menu_Nr); */  /* fuer spaeteren Gebrauch */
  709.  
  710.   switch (Menu)
  711.   {
  712.     case 0:                   /* Copyright, Credits */
  713.       switch (MenuItem)
  714.       {
  715.     case 3:
  716.       Credits();
  717.       break;
  718.       }
  719.       break;
  720.     case 1:                   /* Projekt */
  721.       switch (MenuItem)
  722.       {
  723.     case 0:
  724.       if (dateieinlesen())
  725.         Prepare();
  726.       break;
  727.     case 1:
  728.       dateispeichern(ChemPrefs.IconCreaCDM);
  729.       break;
  730.     case 2:
  731.       if(atomanz)
  732.       {
  733.         if(TwoGadRequest(CONFIRM_DELETION))
  734.         {
  735.           Werte_loeschen();
  736.           atomanz=0;
  737.           strcpy(Dateiname,"");
  738.           strcpy(IFFDateiname,"");
  739.           SimpleRequest(VALUES_DELETED);
  740.         }
  741.       }
  742.       break;
  743.     case 3:
  744.       Bild_speichern();
  745.       break;
  746.     case 4:
  747.       SysInfo();
  748.       break;
  749.     case 5:
  750.       if(TwoGadRequest(CONFIRM_QUIT))
  751.         Close_All(OK);
  752.       break;
  753.       }
  754.       break;
  755.     case 2:                   /* Edit */
  756.       switch (MenuItem)
  757.       {
  758.     case 0:
  759.       if (Eingabe())
  760.         Prepare();                 /* bei OK */
  761.       break;
  762.     case 1:
  763.       Farben();
  764.       break;
  765.       }
  766.       break;
  767.     case 3:                   /* Zeichnen */
  768.       switch (MenuItem)
  769.       {
  770.     case 0:
  771.       Cls(Window1, 0);
  772.       Logo();
  773.       for (n = 1; n <= atomanz; n++)
  774.       {
  775.         aktfarb = farbnr(a[n]);
  776.         atomskizze(a[n]);
  777.       }
  778.       PrintName();
  779.       break;
  780.     case 1:
  781.       Block(Window1, 0, 20, HEIGHT - 12, 280, 11);
  782.       Print(Window1, PRESS_MB, 1, 0, 20, HEIGHT - 6);
  783.       Logo();
  784.       if(ChemPrefs.TimeWindow==TRUE)
  785.         timewindow_on=prepare_zeitinfo(atomanz); /* Zeit-Fenster ÷ffnen */
  786.       else
  787.         timewindow_on=FALSE;
  788.       stime=time(&stime);
  789.       for (n = 1; n <= atomanz; n++)
  790.       {
  791.         aktfarb = farbnr(a[n]);
  792.         if (atomzeichnen(a[n]))   /* solange FALSE, bis Maustaste gedr. */
  793.           break;
  794.         if(timewindow_on)
  795.           zeit_angabe(n,stime,time(NULL));
  796.       }
  797.       etime=time(&etime);
  798.       Block(Window1, 0, 20, HEIGHT - 12, 280, 11);
  799.       PrintName();
  800.       if(timewindow_on)
  801.       {
  802.         CloseWindowSafely(timewin,NULL);
  803.         timewindow_on=FALSE;
  804.       }
  805.       StatRequest(Window1,etime-stime,n-1);
  806.       break;
  807.       }
  808.       break;
  809.     case 4:                   /* Einstellungen */
  810.       switch (MenuItem)
  811.       {
  812.     case 0:
  813.       prefs(&ChemPrefs);
  814.       if(ChemPrefs.bv<1.0)
  815.         ChemPrefs.bv=1.0;
  816.       aspect = ((double) HEIGHT - 26.0) / RESX * ChemPrefs.bv;
  817.       break;
  818.       }
  819.       break;
  820.   }
  821. }
  822.  
  823. void      main()                       /* Hauptprogramm            */
  824. {
  825.   Open_All();
  826.   koordmx = round(RESX / 2.0);
  827.   koordmy = round(((double) HEIGHT - 26.0) / 2.0);
  828.   if(HEIGHT<256)
  829.     ChemPrefs.bv=2.0;
  830.   aspect = ((double) HEIGHT - 26.0) / RESX * ChemPrefs.bv;
  831.  
  832.   vergr = VERGRFAKTOR;
  833.   Werte_loeschen();                    /* sicherheitshalber loeschen, damit nicht irgend-
  834.                       welcher Muell vorhanden ist */
  835.   FOREVER
  836.   {
  837.     switch (Nachricht(Window1))
  838.     {
  839.       case MENUPICK:
  840.     Menu_Auswertung(code);
  841.     break;
  842.       case VANILLAKEY:      /* alle diese Features sind nicht dokumentiert,
  843.                  da sie nur fⁿr mich interessant sind! */
  844.     switch(code)
  845.     {
  846.       case 'l':
  847.       case 'L':
  848.         license();
  849.         break;
  850.       case 'N':
  851.         set_screenmode(200);
  852.         break;
  853.       case 'P':
  854.         set_screenmode(256);
  855.         break;
  856.      }
  857.      break;
  858.     }
  859.   }
  860. }
  861.  
  862. /*--------------------------- Unterroutinen ------------------------------*/
  863.  
  864. int Nachricht(win)
  865. struct Window *win;
  866. {
  867.   int        nklasse;
  868.  
  869.   FOREVER
  870.   {
  871.     if ((message = (struct IntuiMessage *) GetMsg(win->UserPort)) == NULL)
  872.     {
  873.       Wait(1L << win->UserPort->mp_SigBit);
  874.       continue;
  875.     }
  876.     nklasse = message->Class;
  877.     code = message->Code;
  878.     GadgetPtr = (struct Gadget *) message->IAddress;
  879.     GadgetID = GadgetPtr->GadgetID;
  880.     ReplyMsg((struct Message *)message);
  881.     while (message = (struct IntuiMessage *) GetMsg(win->UserPort))
  882.       ReplyMsg((struct Message *)message);
  883.     break;
  884.   }
  885.   return (nklasse);
  886. }
  887.  
  888. void Open_All()
  889. {
  890.   conwin = OpenRevWin("CON:120/88/400/80/Chemesthetics");
  891.   if (conwin == -1)
  892.   {
  893.     printf(NO_CONSOLE);
  894.     Close_All(NOK);
  895.   }
  896.  
  897.   if (!(TestFile("libs:req.library")))
  898.   {
  899.     WrConWin(conwin, NO_REQ_LIB);
  900.     Close_All(NOK);
  901.   }
  902.   else
  903.   {
  904.     if (!(ReqBase = (struct ReqLib *) OpenLibrary("req.library",0L)))
  905.     {
  906.       WrConWin(conwin, ERROR_NO_REQ);
  907.       Close_All(NOK);
  908.     }
  909.   }
  910.  
  911.   if (!(IntuitionBase = (struct IntuitionBase *) ReqBase->IntuiLib))
  912.   {
  913.     WrConWin(conwin, NO_INTUI);
  914.     Close_All(NOK);
  915.   }
  916.  
  917.   if (!(GfxBase = (struct GfxBase *) ReqBase->GfxLib))
  918.   {
  919.     WrConWin(conwin, NO_GFX);
  920.     Close_All(NOK);
  921.   }
  922.  
  923.   if (!(TestFile("libs:arp.library")))
  924.   {
  925.     WrConWin(conwin, NO_ARP);
  926.     Close_All(NOK);
  927.   }
  928.  
  929.   if (!(ArpBase = (struct ArpBase *) OpenLibrary(ArpName, ArpVersion)))
  930.   {
  931.     WrConWin(conwin, ERROR_NO_ARP);
  932.     Close_All(NOK);
  933.   }
  934.  
  935.  
  936. #ifdef GERMAN
  937.   if (!(TestFile("chems_g.dat")))
  938. #endif
  939. #ifdef ENGLISH
  940.   if (!(TestFile("chems_e.dat")))
  941. #endif
  942.   {
  943.       WrConWin(conwin, NO_DATA);
  944.       Close_All(NOK);
  945.   }
  946.  
  947.   Load_Datafile();
  948.   sprintf(Ver, "%s V%s", ProgId, Version);
  949.  
  950.   if(GfxBase->DisplayFlags & (UWORD)NTSC)
  951.     HEIGHT=200;
  952.   FirstNewScreen.Height = HEIGHT;
  953.   if (!(FirstScreen = (struct Screen *) OpenScreen(&FirstNewScreen)))
  954.   {
  955.     WrConWin(conwin, NO_SCREEN);
  956.     Close_All(NOK);
  957.   }
  958.  
  959.   LoadRGB4(&FirstScreen->ViewPort, &Pal[0], 16);
  960.  
  961.   if (Metalworx(FirstScreen))
  962.     WrConWin(conwin, NO_METAL_WIN);
  963.  
  964.   HauptFenster.Height = HEIGHT;
  965.   HauptFenster.Screen = FirstScreen;
  966.  
  967.   if (!(Window1 = (struct Window *) OpenWindow(&HauptFenster)))
  968.   {
  969.     WrConWin(conwin, NO_MAIN_WIN);
  970.     Close_All(NOK);
  971.   }
  972.  
  973.   SetMenuStrip(Window1, &Menu1);
  974.   MyProcess = (struct Process *)FindTask((char *)0);
  975.   OldErrorWin = MyProcess->pr_WindowPtr; /* alten Window-Pointer sichern */
  976.   MyProcess->pr_WindowPtr=(APTR) Window1; /* Requests auf neuen Screen */
  977.  
  978. /* Strukturen fⁿr FileRequest vorbereiten */
  979.   FileStr=(struct ReqFileRequester *)ArpAlloc(2048);
  980.   if(!FileStr)
  981.   {
  982.     WrConWin(conwin, ERROR_ALLOC);
  983.     Close_All(NOK);
  984.   }
  985.   FileStr->VersionNumber=REQVERSION;
  986.   FileStr->Title= Titel;
  987.   FileStr->PathName = dn;
  988.   FileStr->Dir = Pfadname;
  989.   FileStr->File = Dateiname;
  990.   FileStr->Flags = FRQCACHINGM|FRQCACHEPURGEM;
  991.   FileStr->dirnamescolor = 8;
  992.   FileStr->devicenamescolor = 4;
  993.   strcpy(Pfadname,"Examples");
  994.  
  995.   license();
  996.   ShowTitle(FirstScreen,ChemPrefs.Title);
  997.   PrepareLogo();
  998.   PrepareEGadgets();
  999. }
  1000.  
  1001. /****************************************
  1002. * Funktion: Alles geoeffnete schliessen *
  1003. ****************************************/
  1004.  
  1005. void Close_All(status)
  1006. BOOL status;
  1007. {
  1008.   MyProcess->pr_WindowPtr=OldErrorWin;    /* alten Window-Pointer wieder
  1009.                        herstellen */
  1010.   if(reqlib_used)
  1011.     PurgeFiles(FileStr);           /* Speicher f. FileListe freigeben */
  1012.   FreeEGadgets();
  1013.   FreeLogo();
  1014.   if (Window1)
  1015.   {
  1016.     ClearMenuStrip(Window1);
  1017.     CloseWindowSafely(Window1, NULL);
  1018.   }
  1019.   if (FirstScreen)
  1020.     CloseScreen(FirstScreen);
  1021.   if (ArpBase)                   /* Arp-Library schliessen und vorher alle */
  1022.     CloseLibrary((struct Library *)ArpBase);   /* Tracked_Items freigeben  */
  1023.   if (ReqBase)
  1024.     CloseLibrary((struct Library *)ReqBase);
  1025.   if (conwin != -1)
  1026.   {
  1027.     WrConWin(conwin, "Thanx! Have a nice day!");
  1028.     Delay(150L);
  1029.     close(conwin);
  1030.   }
  1031.   exit(status);
  1032. }
  1033.